package com.iot.core.springboot;


import com.iot.core.data.BaseDto;
import com.iot.core.data.BaseEntity;
import com.iot.core.data.BaseQto;
import com.iot.core.data.entity.HtError;
import com.iot.core.data.mapper.HtErrorMapper;
import com.iot.core.data.mapper.HtUserLoginMapper;

import com.iot.core.data.service.IHtActionLogService;
import com.iot.core.data.service.IHtErrorService;
import com.iot.core.exception.MyException;
import com.iot.core.exception.MyExceptionUtil;
import com.iot.core.manager.auth.AuthManager;
import com.iot.core.manager.htcls.HtClsManager;
import com.iot.core.manager.htctl.HtCtlActDto;
import com.iot.core.manager.htctl.HtCtlManager;
import com.iot.core.manager.id.HtIdManager;
import com.iot.core.util.MyJSON;
import com.iot.core.util.MyStringUtil;
import com.iot.core.util.RequestUtil;
import com.iot.core.util.ValidatorUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;

@Aspect
@Component
@Slf4j //日志
public class MyAspect {




    @Autowired
    IHtErrorService iHtErrorService;
    @Autowired
    IHtActionLogService iHtActionLogService;

    //抽取公共的切入点表达式
    //1、本类引用
    //2、其他的切面引用
//    @Pointcut("execution(public *  iot..*.controller..*(..))")
//    public void pointCut() {
//    }




    @Around(value = "@annotation(io.swagger.v3.oas.annotations.Operation)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        try {

            var myContext=MyThreadLocal.get();
          //  String signatureShortStr = point.getSignature().toShortString();
            String ctlName=point.getTarget().getClass().getName();
            String actName=point.getSignature().getName();



            var req = ApplicationUtils.getRequest();
            var token=req.getHeader("token");
            var reqUrl=req.getRequestURI().toLowerCase();
            var  mctl= HtCtlManager.getInstance().getCtl(ctlName);
            var  maction= HtCtlManager.getInstance().getAction(mctl.getFullName(),actName);
            if(ObjectUtils.isEmpty(maction) ) {
                var laction=mctl.getActions();
                for(var maction2:laction){
                    if(reqUrl.startsWith(maction2.getFullUrl() )){
                        maction=maction2;
                    }
                }
            }
            myContext.setAction(maction);

            var su=myContext.getSu();
            if(StringUtils.hasText(token)){
                var su2= AuthManager.getInstance().getSuByToken(token);
                if(!ObjectUtils.isEmpty(su2)){
                    if(!su2.isOnline()){
                        throw new MyException( "登录信息失效",401);
                    }
                    BeanUtils.copyProperties(su2,su );
                }
            }
            su.setEdtUrl(reqUrl );

            var  clientInfo= RequestUtil.getClientInfo(req);
            su.setIp(clientInfo.getIP());
            su.setBrowser(clientInfo.getBrowser());
            su.setOs(clientInfo.getOs() );

            var mylog=myContext.getMylog();
            BeanUtils.copyProperties(su,mylog );
            mylog.setId(HtIdManager.getInstance().nextLong());
            mylog.setCrtDt(new Date( ));
            mylog.setHost(req.getServerName()+":"+req.getServerPort() );
            mylog.setHtuserloginId(su.getId() );
            mylog.setUrl( su.getEdtUrl()  );


            Object[] args = point.getArgs();
            for(var i=0;i<args.length;i++) {
                Object arg=args[i];
                if(arg instanceof String argstr){
                    args[i] =argstr.trim();
                }
                else{
                    HtClsManager.getInstance().dealParam(arg);
                }
            }
            if(args.length>0){
                if( args[0] instanceof MultipartFile mf) {
                    //上传文件
                    mylog.setPin(mf.getOriginalFilename() );
                }
                else{
                    myContext.setPIn( args[0] );
                    if(args[0] instanceof BaseEntity be){
                        mylog.setGlid(be.getId()==null?"":be.getId().toString());
                        ValidatorUtils.validateEntity(args[0]);
                    }else if(args[0] instanceof BaseQto bq){
                        mylog.setGlid(bq.getId()==null?"":bq.getId().toString());
                        ValidatorUtils.validateEntity(args[0]);
                    } else if(args[0] instanceof BaseDto bd){
                        mylog.setGlid(bd.getId()==null?"":bd.getId().toString());
                        ValidatorUtils.validateEntity(args[0]);
                    }else{
                        var glid=HtClsManager.getInstance().getFieldStrV(args[0],"Id");
                        mylog.setGlid(glid);
                    }
                }

            }

            if(!ObjectUtils.isEmpty(maction)){
                if(maction.getAuthType().toString().equals("Login")){
                    if(su.getId().equals(0L)){
                        throw new MyException( "请登录",401);
                    }
                } else if (maction.getAuthType().toString().equals("Auth")) {
                    var b=AuthManager.getInstance().hasUrl(su,maction.getFullUrl() );
                    if(!b){
                        throw new MyException( "请登录",401);
                    }
                }
            }

            Object result = point.proceed();



            if(!ObjectUtils.isEmpty(maction) &&( maction.isLogNeed()||su.isDebug() )){

                if(maction.isLogPin()){
                    if(!ObjectUtils.isEmpty(myContext.getPIn())){
                        mylog.setPin(MyJSON.toJSONString( myContext.getPIn() ));
                    }
                }

                if(maction.isLogPout()){
                    if(!ObjectUtils.isEmpty(result) ){
                        mylog.setPout(MyJSON.toJSONString(result));
                    }
                }

                long mseconds=  new Date().getTime()-mylog.getCrtDt().getTime();
                mylog.setMseconds((int) mseconds);
                dealLogMemo(myContext,maction,result);
                iHtActionLogService.saveLogAsync(mylog);
            }

            return result;
        }
        catch (Exception ex){
            addDB(ex);
            throw  ex;
        }
        finally {
            MyThreadLocal.remove();
        }

    }

    void dealLogMemo(MyContext myContext , HtCtlActDto mact, Object pout)
    {
        try{

            dealLogMemoF(myContext,mact,pout);
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
    void dealLogMemoF(MyContext myContext ,HtCtlActDto mact, Object pout)
    {
        var mylog=myContext.getMylog();
        if(ObjectUtils.isEmpty(mylog)){
            return;
        }
        if(StringUtils.hasText(mylog.getMemo())){
            return ;
        }
        if(ObjectUtils.isEmpty(mact)){
            return;
        }

        var ActionName = mact.getName();
        var LogTemplete = mact.getLogTemplete();
        LogTemplete = LogTemplete.replace("{ActionName}", ActionName);
        //{ActionName} {Pin.Name}  {Deleted.Name}  {Deleteds.Name} {Inserted.Name} {Inserteds.Count}
        //Pout
        var ib = LogTemplete.indexOf("{");
        while (ib>=0){
            var ie= LogTemplete.indexOf("}",ib);
            if(ie<0)
            {
                break;
            }
            var field = LogTemplete.substring(ib+1, ie  ).trim();
            var arr= field.split("\\.");
            if(arr.length!=2){
                break;
            }
            switch (arr[0]) {
                case "Pin" -> {
                    var svr = HtClsManager.getInstance().getFieldStrV(myContext.getPIn(), arr[1]);
                    LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                }
                case "Pout" -> {
                    var svr = HtClsManager.getInstance().getFieldStrV(pout, arr[1]);
                    LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                }
                case "Inserted" -> {
                    var svr = HtClsManager.getInstance().getFieldStrV(myContext.getInserted(), arr[1]);
                    LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                }
                case "Inserteds" -> {
                    if (arr[1].equals("Count")) {
                        var svr = "" + myContext.getInserteds().size();
                        LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                    } else if (myContext.getInserteds().size() > 0) {
                        var svr = "";
                        for (var mdto : myContext.getInserteds()) {
                            svr += HtClsManager.getInstance().getFieldStrV(mdto, arr[1]) + ",";
                        }
                        svr = MyStringUtil.trimEnd(svr, ",");
                        LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                    }
                }
                case "Deleted" -> {
                    var svr = HtClsManager.getInstance().getFieldStrV(myContext.getDeleted(), arr[1]);
                    LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                }
                case "Deleteds" -> {
                    if (arr[1].equals("Count")) {
                        var svr = "" + myContext.getDeleteds().size();
                        LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                    } else if (myContext.getDeleteds().size() > 0) {
                        var svr = "";
                        for (var mdto : myContext.getDeleteds()) {
                            svr += HtClsManager.getInstance().getFieldStrV(mdto, arr[1]) + ",";
                        }
                        svr = MyStringUtil.trimEnd(svr, ",");
                        LogTemplete = LogTemplete.replace("{" + field + "}", svr);
                    }
                }
                default -> {
                    break;
                }
            }

            ib = LogTemplete.indexOf("{");
        }

        if (!StringUtils.hasText(LogTemplete))
        {
            LogTemplete = ActionName;
        }
        myContext.setLogMemo(LogTemplete);
    }

    void  addDB(Exception e){
        if(e instanceof MyException
                ||e instanceof org.springframework.dao.DuplicateKeyException
                ||e instanceof HttpRequestMethodNotSupportedException
        ){
            return ;
        }
        var m=new HtError();
        var myContext=MyThreadLocal.get();

        var mylog= MyThreadLocal.get().getMylog();
        BeanUtils.copyProperties(mylog,m);
        m.setId(HtIdManager.getInstance().nextLong());
        m.setCrtDt(new Date() );
        m.setExClsname(  MyExceptionUtil.getExClsname(e) );
        m.setExMsg(  MyExceptionUtil.getExMsg(e) );
        m.setExFullmsg(  MyExceptionUtil.getFullmsg(e) );

        if(!ObjectUtils.isEmpty(myContext.getPIn())){
            m.setPin(MyJSON.toJSONString( myContext.getPIn() ));
        }
        if(!ObjectUtils.isEmpty(myContext.getAction())){
            m.setMemo(  myContext.getAction().getName() );
        }

        iHtErrorService.saveLogAsync(m);
    }
}
